﻿using HDF.PInvoke;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace HDF5Demo
{
    public class HDF5Helper
    {
        public static void SaveMatrixToHDF5(string fileName, string datasetName, double[,] matrix)
        {
            long fileId;
            if (System.IO.File.Exists(fileName))
            {
                fileId = H5F.open(fileName, H5F.ACC_RDWR);
            }
            else
            {
                fileId = H5F.create(fileName, H5F.ACC_TRUNC);
            }

            ulong[] dims = { (ulong)matrix.GetLength(0), (ulong)matrix.GetLength(1) };
            long spaceId = H5S.create_simple(dims.Length, dims, null);

            long datasetId;
            if (H5L.exists(fileId, datasetName) > 0)
            {
                H5S.close(spaceId);
                H5F.close(fileId);
                throw new InvalidOperationException($"数据集 '{datasetName}' 已存在。");
            }
            else
            {
                datasetId = H5D.create(fileId, datasetName, H5T.NATIVE_DOUBLE, spaceId);
            }

            GCHandle handle = GCHandle.Alloc(matrix, GCHandleType.Pinned);
            H5D.write(datasetId, H5T.NATIVE_DOUBLE, H5S.ALL, H5S.ALL, H5P.DEFAULT, handle.AddrOfPinnedObject());
            handle.Free();

            H5D.close(datasetId);
            H5S.close(spaceId);
            H5F.close(fileId);

            Console.WriteLine($"矩阵已保存 {fileName}");
        }

        public static double[,] QueryMatrix(string fileName, string datasetName, int startRow, int rowCount, int startCol, int colCount)
        {
            long fileId = H5F.open(fileName, H5F.ACC_RDONLY);
            long datasetId = H5D.open(fileId, datasetName);
            ulong[] offset = { (ulong)startRow, (ulong)startCol };
            ulong[] count = { (ulong)rowCount, (ulong)colCount };
            long spaceId = H5D.get_space(datasetId);
            H5S.select_hyperslab(spaceId, H5S.seloper_t.SET, offset, null, count, null);
            long memSpaceId = H5S.create_simple(2, count, null);
            double[,] buffer = new double[rowCount, colCount];
            GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            H5D.read(datasetId, H5T.NATIVE_DOUBLE, memSpaceId, spaceId, H5P.DEFAULT, handle.AddrOfPinnedObject());
            handle.Free();
            H5S.close(memSpaceId);
            H5S.close(spaceId);
            H5D.close(datasetId);
            H5F.close(fileId);
            return buffer;
        }

        public static double[,] QueryEntireMatrix(string fileName, string datasetName)
        {
            long fileId = H5F.open(fileName, H5F.ACC_RDONLY);
            long datasetId = H5D.open(fileId, datasetName);
            long spaceId = H5D.get_space(datasetId);
            ulong[] dims = new ulong[2];
            H5S.get_simple_extent_dims(spaceId, dims, null);
            double[,] buffer = new double[dims[0], dims[1]];
            GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
            H5D.read(datasetId, H5T.NATIVE_DOUBLE, H5S.ALL, H5S.ALL, H5P.DEFAULT, handle.AddrOfPinnedObject());
            handle.Free();
            H5S.close(spaceId);
            H5D.close(datasetId);
            H5F.close(fileId);
            return buffer;
        }
    }
}
